package com.utils;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Formatter;
import java.util.Properties;

public class LogCustom {
    private final Class<?> clazz;
    private Logger logger;
    private static final String TOP_BORDER = "╔═══════════════════════════════════════════════════════════════════════════════════════════════════";
    private static final String LEFT_BORDER = "║ ";
    private static final String BOTTOM_BORDER = "╚═══════════════════════════════════════════════════════════════════════════════════════════════════";

    /**
     * @param clazz 获取当前类
     */
    public LogCustom(Class<?> clazz) {
        this.clazz = clazz;
        //Logger.getLogger的方法是调用的是LogManager.getLogger()方法，所以这两个方法都是返回logger
        this.logger = Logger.getLogger(this.clazz);
        LogCustom.initlog4j();

    }

    //初始化log4j，设置log4j的配置文件log4j.Properties
    private static void initlog4j() {
        //创建Propderties对象
        Properties prop = new Properties();
	   /*Log4j建议只使用四个级别，优先级从高到低分别是ERROR、WARN、INFO、DEBUG
	   这里定义能显示到的最低级别,若定义到INFO级别,则看不到DEBUG级别的信息了~!级别后面是输出端*/
        prop.setProperty("log4j.rootLogger", "INFO,CONSOLE,E,F");
        prop.setProperty("log4j.appender.CONSOLE", "org.apache.log4j.ConsoleAppender");
        prop.setProperty("log4j.appender.CONSOLE.layout", "org.apache.log4j.PatternLayout");
        prop.setProperty("log4j.appender.CONSOLE.layout.ConversionPattern", "[%d{YYYY-MM-dd HH:mm:ss,SSS}] %-5p %c %m%n");

        String src = "test-output/logCustom";
        //设置日期格式
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm");
        //获取当前日期
        String date = dateFormat.format(new Date()).toString();

        File dir = new File(src + "/" + date);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        String filepath = dir.getAbsolutePath() + "/" + "log_" + date + ".logCustom";

        prop.setProperty("log4j.appender.E", "org.apache.log4j.FileAppender");
        prop.setProperty("log4j.appender.E.file", filepath);
        prop.setProperty("log4j.appender.E.layout", "org.apache.log4j.PatternLayout");
        prop.setProperty("log4j.appender.E.layout.ConversionPattern", "[%d{YYYY-MM-dd HH:mm:ss,SSS}] %-5p %c %m%n");
        prop.setProperty("log4j.appender.F", "org.apache.log4j.FileAppender");
        prop.setProperty("log4j.appender.file.encoding", "UTF-8");
        //String src="test-output/logCustom";
        //设置日期格式
        //SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd");
        //获取当前日期
        //String date=dateFormat.format(new Date()).toString();
        //设置时间格式
        //SimpleDateFormat timeFormat=new SimpleDateFormat("yyyy-MM-dd HHmmss");
        //获取当前时间
        //String time=timeFormat.format(new Date()).toString();
        //File dir = new File(src+"/"+date);
        // if (!dir.exists())
        // {dir.mkdirs();}
        String filepathHtml = dir.getAbsolutePath() + "/" + "log_" + date + ".html";
        prop.setProperty("log4j.appender.F.file", filepathHtml);
        prop.setProperty("log4j.appender.F.layout", "org.apache.log4j.HTMLLayout");
        //prop.setProperty("log4j.appender.F.layout.ConversionPattern", "[%d{YYYY-MM-dd HH:mm:ss,SSS}] %-5p %c %m%n");

        PropertyConfigurator.configure(prop);
    }

    public void info(String message) {
        logger.info(message);
    }

    public void warn(String message) {
        logger.warn(message);
    }

    public void error(String message) {
        log("错", message);
    }

    public void debug(String message) {
        logger.debug(message);
    }

    private void log(String tag, Object... contents) {
        if (!sLogSwitch) return;
        final String[] processContents = processContents(tag, contents);
        tag = processContents[0];
        String msg = processContents[1];
        printLog(tag, msg);
    }

    private void printLog(String tag, String msg) {
        if (sLogBorderSwitch) print(tag, TOP_BORDER);
        int len = msg.length();
        int countOfSub = len / MAX_LEN;
        if (countOfSub > 0) {
            print(tag, msg.substring(0, MAX_LEN));
            String sub;
            int index = MAX_LEN;
            for (int i = 1; i < countOfSub; i++) {
                sub = msg.substring(index, index + MAX_LEN);
                print(tag, (sLogBorderSwitch ? LEFT_BORDER : "") + sub);
                index += MAX_LEN;
            }
            sub = msg.substring(index, len);
            print(tag, (sLogBorderSwitch ? LEFT_BORDER : "") + sub);
        } else {
            print(tag, msg);
        }
        if (sLogBorderSwitch) print(tag, BOTTOM_BORDER);
    }

    private void print(final String tag, String msg) {
        logger.error(tag + ">>>" + msg);
    }

    private String[] processContents(String tag, Object... contents) {
        StackTraceElement targetElement = Thread.currentThread().getStackTrace()[5];
        String className = targetElement.getClassName();
        String[] classNameInfo = className.split("\\.");
        if (classNameInfo.length > 0) {
            className = classNameInfo[classNameInfo.length - 1];
        }
        if (className.contains("$")) {
            className = className.split("\\$")[0];
        }
        if (!sTagIsSpace) {// 如果全局tag不为空，那就用全局tag
            tag = sGlobalTag;
        } else {// 全局tag为空时，如果传入的tag为空那就显示类名，否则显示tag
            tag = isSpace(tag) ? className : tag;
        }
        String head = sLogHeadSwitch
                ? new Formatter()
                .format("Thread: %s, %s(%s.java:%d)" + LINE_SEPARATOR,
                        Thread.currentThread().getName(),
                        targetElement.getMethodName(),
                        className,
                        targetElement.getLineNumber()).toString()
                : "";
        String body = NULL_TIPS;
        if (contents != null) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0, len = contents.length; i < len; ++i) {
                Object content = contents[i];
                sb.append(ARGS)
                        .append("[")
                        .append(i)
                        .append("]")
                        .append(" = ")
                        .append(content == null ? NULL : content.toString())
                        .append(LINE_SEPARATOR);
            }
            body = sb.toString();
        }
        String msg = head + body;
        if (sLogBorderSwitch) {
            StringBuilder sb = new StringBuilder();
            String[] lines = msg.split(LINE_SEPARATOR);
            for (String line : lines) {
                sb.append(LEFT_BORDER).append(line).append(LINE_SEPARATOR);
            }
            msg = sb.toString();
        }
        return new String[]{tag, msg};
    }

    private boolean isSpace(String s) {
        if (s == null) return true;
        for (int i = 0, len = s.length(); i < len; ++i) {
            if (!Character.isWhitespace(s.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    private final int MAX_LEN = 4000;
    private boolean sLogSwitch = true; // log总开关，默认开
    private String sGlobalTag = null; // log标签
    private boolean sLogHeadSwitch = true; // log头部开关，默认开
    private boolean sTagIsSpace = true; // log标签是否为空白
    private final String NULL_TIPS = "Log with null object.";
    private final String NULL = "null";
    private final String ARGS = "args";
    private final String LINE_SEPARATOR = System.getProperty("line.separator");
    private boolean sLogBorderSwitch = true; // log边框开关，默认开
}

